/**
  ******************************************************************************
  * @file    nuc it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
**/
#include "gd32f10x.h"
#include "osObjects.h"
#include "sys.h"
#include "flashtoeep.h"
#include "extnorflashlog.h"
#include "extblockflashlog.h"
#include "gd25q_cmd.h"

void FlashErase(uint32_t AddrBase, uint32_t Nums);
void FlashProgram(uint32_t Addr, uint32_t Data);
void FlashMulwProgram(uint32_t Addr, uint16_t * Data, uint16_t Len);
void FlashMulbProgram(uint32_t Addr, uint8_t * Data, uint16_t Len);

void FlashUnlock(void);
void FlashLock(void);
uint8_t gd25_erase(uint32_t AddrBase, uint32_t Nums);
void log_buff_full_callback(void);

uint16_t FlashMulEepRead(FlashEepCfg_Type *EepCfg);
uint16_t FlashMulEepSave(FlashEepCfg_Type *EepCfg);

volatile uint16_t  UserParSaveCnt;
volatile uint16_t  SysParSaveCnt;
volatile uint16_t  PrgParSaveCnt;

uint16_t ParTab[128];
uint16_t ProgTab[130];
uint8_t LogBuff[64];

uint32_t flash_work_buff[4*1024+4];


#define INEEP_ADDR_SYS           (0x8000000+0x7E000) //4KB
#define INEEP_ADDR_PRG           (0x8000000+0x7C000) //4KB
#define INEEP_ADDR_LOG_BUFF      (0x8000000+0x40000) //128KB


FlashEepInfo_Type EepInfoSys = {0};
FlashEepInfo_Type EepInfoPrg = {0};

ext_nor_log_Info_Type nor_log_info = {0};
flash_log_man_info_Type log_man_buff_info = {0};




FlashEepCfg_Type EepCfgSys =
{
    1024*2,
    1024*4,
    64,
    64,
    INEEP_ADDR_SYS,
    (uint16_t*)&ParTab[0],
    &EepInfoSys,
    &FlashErase,
    &FlashProgram,
    &FlashUnlock,
    &FlashLock,
};

FlashEepCfg_Type EepCfgPrg =
{
    1024*2,
    1024*8,
    256,
    256,
    INEEP_ADDR_PRG,
    (uint16_t*)&ProgTab[0],
    &EepInfoPrg,
    &FlashErase,
    &FlashProgram,
    &FlashUnlock,
    &FlashLock,
};

ext_nor_log_Cfg_Type nor_log_cfg = 
{
    4*1024,
    4*1024*1024,
    16,
    16,
    1*1024*1024,
    LogBuff,
    flash_work_buff,
    &nor_log_info,
    &gd25_erase,
    &gd25qWrite,
    &gd25qRead,
};

flash_log_man_cfg_Type log_man_buff_cfg = 
{
    INEEP_ADDR_LOG_BUFF,
    1024*2,
    64,
    32,
    32,
    (uint16_t*)&LogBuff[0],
    &log_man_buff_info,
    &FlashErase,
    &FlashMulwProgram,
    &FlashUnlock,
    &FlashLock,
    &log_buff_full_callback
};

/*****************************************************************************//*!
*
*****************************************************************************/
void flashtask(void   *argument)
{


    uint32_t Cnt;
    
		osDelay(500);
	
    FlashEepRead(&EepCfgSys);
    FlashMulEepRead(&EepCfgPrg);
    ext_nor_log_FlashCheck(&nor_log_cfg);
    
    if(ParTab[0]==0xFFFF)
    {
        Cnt = 128;
        while(Cnt--)
            ParTab[Cnt] = 1;
        FlashEepSave(&EepCfgSys);
    }
    
    if((ProgTab[0]==0xFFFF)&&(ProgTab[1]==0xFFFF))
    {
        Cnt = 128;
        while(Cnt--)
            ProgTab[Cnt] = 1;
        
        FlashMulEepSave(&EepCfgPrg);
    }
    
    for(;;)
    {
        osDelay(5);
        
        if(SysParSaveCnt)
        {
            uint16_t val;
            val = ParTab[0];
            val++;
            if(val == 0xFFFF)
                val ++;
            Cnt = 128;
            while(Cnt--)
                ParTab[Cnt] = val;
        
            SysParSaveCnt--;
            FlashEepSave(&EepCfgSys);
        }
        osDelay(5);

        
        if(PrgParSaveCnt)
        {
            Cnt = 128;

            uint16_t val;
            val = ProgTab[0];
            val++;
            if(val == 0xFFFF)
                val ++;
            Cnt = 128;
            while(Cnt--)
                ProgTab[Cnt] = val;
            
            PrgParSaveCnt--;
            FlashMulEepSave(&EepCfgPrg);
        }
    }
}

/*****************************************************************************//*!
*
*****************************************************************************/
volatile uint32_t fmc_ok_cnt;
volatile uint32_t fmc_err_cnt;
volatile fmc_state_enum fmc_st;
volatile uint32_t fmc_addr;

void FlashErase(uint32_t AddrBase, uint32_t Nums)
{
    while(Nums--)
    {
        fmc_st = fmc_page_erase(AddrBase);
        AddrBase+=2048;
        fmc_addr= AddrBase;
        
        if(fmc_st != FMC_READY)
        {
            fmc_err_cnt++;
            NOP1();
            NOP1();
            NOP1();
            NOP1();
        }
    }
}

void FlashProgram(uint32_t Addr, uint32_t Data)
{ 
    fmc_st = fmc_word_program(Addr, Data);
    fmc_addr= Addr;
    if(fmc_st == FMC_READY)
    {
        fmc_ok_cnt++;
    }
    else
    {
        fmc_err_cnt++;
        if(fmc_err_cnt > fmc_ok_cnt)
        fmc_ok_cnt = 0;
    }    
    
}

void FlashMulwProgram(uint32_t Addr, uint16_t * Data, uint16_t Len)
{
    uint32_t Dataw;
    uint32_t AddrNow;
    
    if(Len & 0x01)
    {
        return;
    
    } else {
        AddrNow = Addr + Len*2 - 4;
        
        while(1)
        {
            Dataw = Data[--Len];
            Dataw <<= 16;
            Dataw += Data[--Len];
            fmc_word_program(Addr, Dataw);
            AddrNow-=4;
            if((AddrNow < Addr) || (Len > (4096)))
                break;
        }
    }
}

void FlashUnlock(void)
{
    INTX_DISABLE();
    fmc_unlock();
    INTX_ENABLE();
}
void FlashLock(void)
{
    INTX_DISABLE();
    fmc_lock();
    INTX_ENABLE();
}

uint8_t gd25_erase(uint32_t AddrBase, uint32_t Nums)
{
    while(Nums--)
    {
        gd25qSectorErase(AddrBase);
        AddrBase+=4*1024;
    }
    
    return 0;
}

void log_buff_full_callback(void)
{
    
}
